package chapter5;

import lombok.extern.slf4j.Slf4j;

import java.util.Iterator;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * @author caiya
 * @date 2020/3/29 19:39
 */
@Slf4j
public class ArrayBlockingQueueTest {
    static ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(5);

    public static void main(String[] args) throws InterruptedException {
        /**
         * ArrayBlockingQueue：基于数组的有界阻塞队列
         * 1、原理：
         *      底层基于数组，使用cas保证以下方法的原子性
         * 2、boolean offer(E e)：非阻塞式插入
         *      1）队列有空间，插入成功返回 true
         *      2）队列满插入失败返回 false
         *      3）e 为空时，抛出 NPE
         * 3、void put(E e)：阻塞插入
         *      1）队尾插入
         *      2）队列满时，阻塞当前线程（condition.await），直到队列有空闲插入成功后返回
         *      3）可能会抛出 InterruptedException 异常（步骤2被阻塞时可能会被别的线程interrupt）
         *      4）e 不允许为 null，否则 NPE
         * 4、E poll()：非阻塞获取并移除
         *      1）队首获取并移除元素
         *      2）如果队列为空，则返回 null
         * 5、E take()：阻塞式获取并删除
         *      1）队首获取并移除元素
         *      2）队列为空时，阻塞当前线程（condition.await），直到队列不为空然后获取元素并删除
         *      3）可能会抛出 InterruptedException 异常（步骤2被阻塞时可能会被interrupt）
         * 6、E peek()：非阻塞获取但不移除
         *      1）队首获取但是不移除元素
         *      2）如果队列为空，则返回 null
         * 7、int size()：获取队列大小（准确，放心使用）
         */
        log.debug("arrayBlockingQueue.size(): {}", arrayBlockingQueue.size());
        log.debug("arrayBlockingQueue.poll(): {}", arrayBlockingQueue.poll());

        arrayBlockingQueue.offer("张三");
        arrayBlockingQueue.offer("王五");
        arrayBlockingQueue.offer("李四");
        arrayBlockingQueue.offer("王五");

        log.debug("arrayBlockingQueue.size(): {}", arrayBlockingQueue.size());

        // poll获取队首元素后，size-1
        log.debug("arrayBlockingQueue.poll(): {}", arrayBlockingQueue.poll());
        log.debug("arrayBlockingQueue.size(): {}", arrayBlockingQueue.size());

        // peek获取队首元素后，size不变
        log.debug("arrayBlockingQueue.peek(): {}", arrayBlockingQueue.peek());
        log.debug("arrayBlockingQueue.size(): {}", arrayBlockingQueue.size());

        // 删除的元素有很多时，只会删除排在最前面的那个，并返回true
        log.debug("arrayBlockingQueue.remove(): {}", arrayBlockingQueue.remove("法斯特"));
        log.debug("arrayBlockingQueue.remove(): {}", arrayBlockingQueue.remove("王五"));
        log.debug("arrayBlockingQueue.size(): {}", arrayBlockingQueue.size());

        // remove只删除了一个 "王五"，所以contains返回true
        log.debug("arrayBlockingQueue.contains(): {}", arrayBlockingQueue.contains("王五"));

        Iterator<String> iterator = arrayBlockingQueue.iterator();
        while (iterator.hasNext()) {
            String e = iterator.next();
            log.debug(e);
        }

        arrayBlockingQueue.put("王五");
        arrayBlockingQueue.put("王五");
        arrayBlockingQueue.put("王五");

        new Thread(() -> {
            try {
                Thread.sleep(3000);
                arrayBlockingQueue.poll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // 队列大小为5，再插入就会阻塞挂起到当前位置，直到队列可以继续 put，再返回从阻塞的地方继续执行
        arrayBlockingQueue.put("王五");

        log.debug("【3s后打印】arrayBlockingQueue.size(): {}", arrayBlockingQueue.size());
    }
}
